home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / ldb / interrupt.c < prev    next >
C/C++ Source or Header  |  1991-11-07  |  11KB  |  400 lines

  1. /* $Header: interrupt.c,v 1.31 91/11/07 00:08:17 wlott Exp $ */
  2.  
  3. /* Interrupt handing magic. */
  4.  
  5. #include <stdio.h>
  6.  
  7. #include <signal.h>
  8. #ifdef mips
  9. #include <mips/cpu.h>
  10. #endif
  11.  
  12. #include "ldb.h"
  13.  
  14. #include "os.h"
  15. #include "arch.h"
  16. #include "lisp.h"
  17. #include "globals.h"
  18. #include "lispregs.h"
  19. #include "interrupt.h"
  20. #include "validate.h"
  21.  
  22. #define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
  23.  
  24. boolean internal_errors_enabled = 0;
  25.  
  26. struct sigcontext *lisp_interrupt_contexts[MAX_INTERRUPTS];
  27.  
  28. union interrupt_handler interrupt_handlers[NSIG];
  29. SIGHDLRTYPE (*interrupt_low_level_handlers[NSIG])() = {0};
  30.  
  31. static int pending_signal = 0, pending_code = 0, pending_mask = 0;
  32. static boolean maybe_gc_pending = FALSE;
  33.  
  34.  
  35. /****************************************************************\
  36. * Utility routines used by various signal handlers.              *
  37. \****************************************************************/
  38.  
  39. void fake_foreign_function_call(context)
  40.      struct sigcontext *context;
  41. {
  42.     int context_index;
  43.     lispobj oldcont;
  44.     
  45.     /* Get current LISP state from context */
  46. #ifndef ibmrt
  47.     current_dynamic_space_free_pointer = (lispobj *) context->sc_regs[ALLOC];
  48.     current_binding_stack_pointer = (lispobj *) context->sc_regs[BSP];
  49. #endif
  50. #ifdef mips
  51.     current_flags_register = context->sc_regs[FLAGS]|(1<<flag_Atomic);
  52. #endif
  53.     
  54.     /* Build a fake stack frame */
  55.     current_control_frame_pointer = (lispobj *) context->sc_regs[CSP];
  56.     if ((lispobj *)context->sc_regs[CFP]==current_control_frame_pointer) {
  57.         /* There is a small window during call where the callee's frame */
  58.         /* isn't built yet. */
  59.         if (LowtagOf(context->sc_regs[CODE]) == type_FunctionPointer) {
  60.             /* We have called, but not built the new frame, so
  61.                build it for them. */
  62.             current_control_frame_pointer[0] = context->sc_regs[OCFP];
  63.             current_control_frame_pointer[1] = context->sc_regs[LRA];
  64.             current_control_frame_pointer += 8;
  65.             /* Build our frame on top of it. */
  66.             oldcont = (lispobj)context->sc_regs[CFP];
  67.         }
  68.         else {
  69.             /* We haven't yet called, build our frame as if the
  70.                partial frame wasn't there. */
  71.             oldcont = (lispobj)context->sc_regs[OCFP];
  72.         }
  73.     }
  74.     /* ### We can't tell if we are still in the caller if it had to
  75.        allocate the stack frame due to stack arguments. */
  76.     /* ### Can anything strange happen during return? */
  77.     else
  78.         /* Normal case. */
  79.         oldcont = (lispobj)context->sc_regs[CFP];
  80.     
  81.     current_control_stack_pointer = current_control_frame_pointer + 8;
  82.  
  83.     current_control_frame_pointer[0] = oldcont;
  84.     current_control_frame_pointer[1] = NIL;
  85.     current_control_frame_pointer[2] = (lispobj)context->sc_regs[CODE];
  86.     
  87. #ifdef mips
  88.     /* Restore the GP */
  89.     set_global_pointer(saved_global_pointer);
  90. #endif
  91.     
  92.     /* Do dynamic binding of the active interrupt context index
  93.        and save the context in the context array. */
  94.     context_index = SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX)>>2;
  95.     
  96.     if (context_index >= MAX_INTERRUPTS) {
  97.         fprintf("Maximum number (%d) of interrupts exceeded.  Exiting.\n",
  98.                 MAX_INTERRUPTS);
  99.         exit(1);
  100.     }
  101.     
  102.     bind_variable(FREE_INTERRUPT_CONTEXT_INDEX, fixnum(context_index + 1));
  103.     
  104.     lisp_interrupt_contexts[context_index] = context;
  105.     
  106.     /* No longer in Lisp now. */
  107.     foreign_function_call_active = 1;
  108. }
  109.  
  110. void undo_fake_foreign_function_call(context)
  111.      struct sigcontext *context;
  112. {
  113.     /* Block all blockable signals */
  114.     sigblock(BLOCKABLE);
  115.     
  116.     /* Going back into lisp. */
  117.     foreign_function_call_active = 0;
  118.     
  119.     /* Undo dynamic binding. */
  120.     /* ### Do I really need to unbind_to_here()? */
  121.     unbind();
  122.     
  123. #ifndef ibmrt
  124.     /* Put the dynamic space free pointer back into the context. */
  125.     context->sc_regs[ALLOC] =
  126.         (unsigned long) current_dynamic_space_free_pointer;
  127. #endif
  128. }
  129.  
  130. #define call_maybe_gc() \
  131.     call_into_lisp(MAYBE_GC, SymbolFunction(MAYBE_GC), \
  132.                    current_control_stack_pointer, 0)
  133.  
  134. void interrupt_internal_error(signal, code, context, continuable)
  135.      struct sigcontext *context;
  136.      boolean continuable;
  137. {
  138.     lispobj *args;
  139.  
  140.     if (internal_errors_enabled) {
  141.     sigsetmask(context->sc_mask);
  142.     fake_foreign_function_call(context);
  143.     args = current_control_stack_pointer;
  144.     current_control_stack_pointer += 2;
  145.     args[0] = alloc_sap(context);
  146.     if (continuable)
  147.         args[1] = T;
  148.     else
  149.         args[1] = NIL;
  150.     call_into_lisp(INTERNAL_ERROR, SymbolFunction(INTERNAL_ERROR),
  151.                args, 2);
  152.     undo_fake_foreign_function_call(context);
  153.     if (continuable)
  154.         arch_skip_instruction(context);
  155.     }
  156.     else
  157.     interrupt_handle_now(signal, code, context);
  158. }
  159.  
  160. void interrupt_handle_pending(context)
  161.      struct sigcontext *context;
  162. {
  163.     if (foreign_function_call_active)
  164.     crap_out("Oh no, got a PendingInterrupt while foreign function call was active.\n");
  165.  
  166. #ifdef mips
  167.     context->sc_regs[FLAGS] &= ~(1<<flag_Interrupted);
  168. #else
  169.     SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, 0);
  170. #endif
  171.     SetSymbolValue(INTERRUPT_PENDING, NIL);
  172.     if (maybe_gc_pending) {
  173.     maybe_gc_pending = FALSE;
  174.     fake_foreign_function_call(context);
  175.     call_maybe_gc();
  176.     undo_fake_foreign_function_call(context);
  177.     }
  178.     if (pending_signal) {
  179.     int signal, code;
  180.  
  181.     signal = pending_signal;
  182.     code = pending_code;
  183.     pending_signal = 0;
  184.     pending_code = 0;
  185.     interrupt_handle_now(signal, code, context);
  186.     }
  187.     context->sc_mask = pending_mask;
  188.     pending_mask = 0;
  189.     arch_skip_instruction(context);
  190. }
  191.  
  192.  
  193. /****************************************************************\
  194. * interrupt_handle_now, maybe_now_maybe_later                    *
  195. *    the two main signal handlers.                               *
  196. \****************************************************************/
  197.  
  198. SIGHDLRTYPE interrupt_handle_now(signal, code, context)
  199. int signal, code;
  200. struct sigcontext *context;
  201. {
  202.     int were_in_lisp;
  203.     union interrupt_handler handler;
  204.     lispobj *args;
  205.     lispobj callname, function;
  206.     
  207.     handler = interrupt_handlers[signal];
  208.  
  209.     if(handler.c==SIG_IGN)
  210.     return;
  211.  
  212.     were_in_lisp = !foreign_function_call_active;
  213.     if (were_in_lisp)
  214.         fake_foreign_function_call(context);
  215.     
  216.     /* Allow signals again. */
  217.     sigsetmask(context->sc_mask);
  218.  
  219.     if(handler.c==SIG_DFL){
  220.     /* This can happen if someone tries to ignore or default on of the */
  221.     /* signals we need for runtime support. */
  222.     fprintf(stderr,"interrupt_handle_now: No handler for signal %d?\n",signal);
  223.     printf("[exit debugger to continue]\n");
  224.     ldb_monitor();
  225.     }
  226.     else if (LowtagOf(handler.lisp) == type_EvenFixnum ||
  227.         LowtagOf(handler.lisp) == type_OddFixnum)
  228.         (*handler.c)(signal, code, context);
  229.     else {
  230.         args = current_control_stack_pointer;
  231.         current_control_stack_pointer += 3;
  232.         args[0] = fixnum(signal);
  233.         args[1] = fixnum(code);
  234.         args[2] = alloc_sap(context);
  235.         callname = handler.lisp;
  236.         if (LowtagOf(callname) == type_FunctionPointer)
  237.             function = callname;
  238.         else
  239.             function = ((struct symbol *)PTR(callname))->function;
  240.         call_into_lisp(callname, function, args, 3);
  241.     }
  242.     
  243.     if (were_in_lisp)
  244.         undo_fake_foreign_function_call(context);
  245. }
  246.  
  247. static SIGHDLRTYPE maybe_now_maybe_later(signal, code, context)
  248. int signal, code;
  249. struct sigcontext *context;
  250. {
  251.     if (SymbolValue(INTERRUPTS_ENABLED) == NIL) {
  252.         pending_signal = signal;
  253.         pending_code = code;
  254.         pending_mask = context->sc_mask;
  255.         context->sc_mask |= BLOCKABLE;
  256.         SetSymbolValue(INTERRUPT_PENDING, T);
  257.     } else if ((!foreign_function_call_active)
  258. #ifdef mips
  259.                && (context->sc_regs[FLAGS] & (1<<flag_Atomic))
  260. #else
  261.            && (SymbolValue(PSEUDO_ATOMIC_ATOMIC))
  262. #endif               
  263.                ) {
  264.         pending_signal = signal;
  265.         pending_code = code;
  266.         pending_mask = context->sc_mask;
  267.         context->sc_mask |= BLOCKABLE;
  268. #ifdef mips
  269.         context->sc_regs[FLAGS] |= (1<<flag_Interrupted);
  270. #else
  271.     SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, T);
  272. #endif
  273.     } else
  274.         interrupt_handle_now(signal, code, context);
  275. }
  276.  
  277. /****************************************************************\
  278. * Stuff to detect and handle hitting the gc trigger.             *
  279. \****************************************************************/
  280.  
  281. #ifndef ibmrt
  282. static boolean gc_trigger_hit(context)
  283.      struct sigcontext *context;
  284. {
  285.  
  286.     if (current_auto_gc_trigger == NULL)
  287.     return FALSE;
  288.     else{
  289.     lispobj *badaddr=(lispobj *)arch_get_bad_addr(context);
  290.  
  291.     return (badaddr >= current_auto_gc_trigger &&
  292.         badaddr < current_dynamic_space + DYNAMIC_SPACE_SIZE);
  293.     }
  294. }
  295. #endif
  296.  
  297.  
  298. boolean interrupt_maybe_gc(context)
  299. struct sigcontext *context;
  300. {
  301.     if (!foreign_function_call_active
  302. #ifndef ibmrt
  303.           && gc_trigger_hit(context)
  304. #endif
  305.     ) {
  306. #ifdef mips
  307.     set_global_pointer(saved_global_pointer);
  308. #endif
  309. #ifndef ibmrt
  310.     clear_auto_gc_trigger();
  311. #endif
  312.  
  313.     if (
  314. #ifdef mips
  315.         context->sc_regs[FLAGS] & (1<<flag_Atomic)
  316. #else
  317.         SymbolValue(PSEUDO_ATOMIC_ATOMIC)
  318. #endif
  319.         ) {
  320.         maybe_gc_pending = TRUE;
  321.         if (pending_signal == 0) {
  322.         pending_mask = context->sc_mask;
  323.         context->sc_mask |= BLOCKABLE;
  324.         }
  325. #ifdef mips
  326.         context->sc_regs[FLAGS] |= (1<<flag_Interrupted);
  327. #else
  328.         SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, T);
  329. #endif
  330.     }
  331.     else {
  332.         fake_foreign_function_call(context);
  333.         call_maybe_gc();
  334.         undo_fake_foreign_function_call(context);
  335.     }
  336.  
  337.     return TRUE;
  338.     }else
  339.     return FALSE;
  340. }
  341.  
  342. /****************************************************************\
  343. * Noise to install handlers.                                     *
  344. \****************************************************************/
  345.  
  346. void interrupt_install_low_level_handler(signal,handler)
  347. int signal;
  348. SIGHDLRTYPE (*handler)();
  349. {
  350.     struct sigvec sv;
  351.  
  352.     sv.sv_handler=handler;
  353.     sv.sv_mask=BLOCKABLE;
  354.     sv.sv_flags=0;
  355.  
  356.     sigvec(signal,&sv,NULL);
  357.  
  358.     interrupt_low_level_handlers[signal]=(handler==SIG_DFL ? 0 : handler);
  359. }
  360.  
  361. unsigned long install_handler(signal, handler)
  362. int signal;
  363. SIGHDLRTYPE (*handler)();
  364. {
  365.     struct sigvec sv;
  366.     int oldmask;
  367.     union interrupt_handler oldhandler;
  368.  
  369.     oldmask = sigblock(sigmask(signal));
  370.  
  371.     if(interrupt_low_level_handlers[signal]==0){
  372.     if(handler==SIG_DFL || handler==SIG_IGN)
  373.         sv.sv_handler=handler;
  374.     else if (sigmask(signal)&BLOCKABLE)
  375.         sv.sv_handler = maybe_now_maybe_later;
  376.     else
  377.         sv.sv_handler = interrupt_handle_now;
  378.  
  379.     sv.sv_mask = BLOCKABLE;
  380.     sv.sv_flags = 0;
  381.  
  382.     sigvec(signal, &sv, NULL);
  383.     }
  384.  
  385.     oldhandler = interrupt_handlers[signal];
  386.     interrupt_handlers[signal].c = handler;
  387.  
  388.     sigsetmask(oldmask);
  389.  
  390.     return (unsigned long)oldhandler.lisp;
  391. }
  392.  
  393. interrupt_init()
  394. {
  395.     int i;
  396.  
  397.     for (i = 0; i < NSIG; i++)
  398.         interrupt_handlers[i].c = SIG_DFL;
  399. }
  400.